<template>
	<view class="chat-container" :style="pageHeight">
		<up-navbar :title="friend?.username" @leftClick="back" 	:rightIcon="isWorkNotice ? '' : 'more-dot-fill'" placeholder @rightClick="rightClick"></up-navbar>
		<h-watermark :title="imInfo?.username" :mobile="imInfo?.phone.slice(-4)" :titleSize="14" :mobileSize="14" :column="6"></h-watermark>

		<z-paging
			:style="{ marginBottom: isWorkNotice ? '10rpx' : '0' }"
			ref="paging"
			v-model="talkList"
			use-chat-record-mode
			safe-area-inset-bottom
			use-safe-area-placeholder
			auto-to-bottom-when-chat
			auto-show-system-loading
			bottom-bg-color="#f8f8f8"
			:paging-style="{ paddingTop: chatBoxHeight }"
			@query="queryList"
			@keyboardHeightChange="keyboardHeightChange"
			@hidedKeyboard="hidedKeyboard"
		>
			<view class="talk-list">
			  <view v-for="(item, index) in talkList" :key="item.id" style="position: relative;">
			    <view style="transform: scaleY(-1);">
			      <view style="text-align: center">
			        <view class="timestamp" v-if="showTimestamp(index)">
			          {{ setTimestamp(index) }}
			        </view>
			      </view>
			      <view class="revoke" v-if="item.status == 12">
			        <text v-if="item.from_account == imInfo.account">你撤回了一条消息<text v-if="item.content[0].type == 'text'" @click="handleReedit(item)" class="reEdit">重新编辑</text></text>
			        <text v-else>{{ item.fromname }}撤回了一条消息</text>
			      </view>
			      <view v-else class="item flex-col" :class="item.from_account != friend.friend_account ? 'push' : 'pull'">
			        <view style="width: 72rpx; height: 72rpx;" @click="jumpPerson(item)">
			          <up-image :src="setUserImg(item.from_phone)" width="72rpx" height="72rpx" radius="10rpx">
			            <template #error>
			              <view style="width: 100%; height: 100%;">
			                <text class="pic-text">{{ showUserName(item.fromname) }}</text>
			              </view>
			            </template>
			          </up-image>
			        </view>
			
			        <view class="msg-item" :class="item.from_account == friend.friend_account ? 'left' : 'right'">
								<view
									class="chat-name"
									:style="{textAlign: item.from_account == friend.friend_account ? 'left' : 'right',
										margin: item.from_account == friend.friend_account ? '0 0 8rpx 14rpx' : '0 14rpx 8rpx 0'
									}"
								>
			            <text v-show="item.from_account != friend.friend_account" style="font-size: 12px; margin-right: 6px;">{{ formatTime(item.send_time) }} [{{item.msg_id}}]</text>
			            {{ item.fromname }}
			            <text v-show="item.from_account == friend.friend_account" style="font-size: 12px; margin-left: 6px;">{{ formatTime(item.send_time) }} [{{item.msg_id}}]</text>
			          </view>
			          <view class="inner" :id="`msg-${item.id}`">
									<view class="content" @longpress="(e) => longpress(e, item)" @touchstart="touchStart" @touchmove="touchMove">
										<view class="reply-msg" @click="replyMsgClick(item?.replyMsg)" v-if="item?.relation_type && item?.relation_type == 'reply'">
											<view class="reply-name">{{ item?.replyMsg?.fromname }}：</view>
											<up-parse :content="item.replyMsg?.html"></up-parse>
										</view>
										<template v-for="item2 in item.content">
											
											<message :dialogId="dialogId" :message="item" :detail="item2" :type="item2.type"></message>

											<view v-show="item.success && item.success == 'loading'" class="send-loading">
												<up-loading-icon :size="14" v-if="item.success == 'loading'"></up-loading-icon>
												<up-icon v-if="item.success == 'error'" name="error-circle-fill" color="red" :size="14"></up-icon>
											</view>
										</template>
									</view>
			          </view>
			
			          <view v-if="item.from_account != friend.friend_account" class="readStatus" :id="item.id">
			            {{ item.status > 0 && item.status < 11 ? '未读' : '已读' }} </view>
			        </view>
			      </view>
			    </view>
			  </view>
			</view>
			
			<!-- 底部聊天输入框 -->
			<template #bottom >
				<chat-input-bar
					v-if="!isWorkNotice"
					ref="inputBar"
					:dialogId="dialogId"
					@send="handleSendClick"
					@callPhone="callPhone"
					@chooseImage="chooseImage"
					@chooseCamera="chooseCamera"
					@chooseFile="chooseFile"
					@copyShow="handleCopyShow"
				/>
				<view v-else style="height: 0rpx;"></view>
			</template>
		</z-paging>

		<up-popup :customStyle="{ width: 'auto', maxWidth: '70vw', height: 'auto', padding: '0' }" :show="copyShow" mode="center" :closeOnClickOverlay="false">
			<view class="copyImgModal">
				<view style="padding: 8px;">
					<image v-if="copyContent === ':/image'" mode="widthFix" style="max-width: 250px;" :src="setCopyImg"></image>
					<view v-if="copyContent === ':/img/text'">
						<up-parse :content="copyStore.copyValue?.html"></up-parse>
					</view>
				</view>
				<view class="footer">
					<view style="border-right: 1px solid #ddd;">
						<up-button @click="copyCancel" :customStyle="{ border: 'none' }" plain type="primary" text="取消"></up-button>
					</view>
					<view>
						<up-button @click="copySend" :customStyle="{ border: 'none' }" plain type="primary" text="确定"></up-button>
					</view>
				</view>
			</view>
		</up-popup>

		<xe-upload ref="XeUpload" :options="uploadOptions" @beforUpload="beforUpload" @callback="handleUploadCallback"></xe-upload>
	
		<PopoverMenu ref="popoverMenu" :friend="friend" :currentMsg="currentMsg" :popStyle="popStyle" @handleReply="handleReply" @handleRevoke="handleRevoke"></PopoverMenu>
	</view>
</template>

<script>
import { chatApi } from '@/apis/cloud/chat'
import { useChatStore, useSocketStore, useUserStore, useCopyStore } from '@/pinia-store/user'
import { getScaledImageSize, chooseFile, fileTypeFormat, formatFileSize, getTimeStringAutoShort, setIcon, processImageUrl } from "@/utils/chat"
import { chooseFileAndroid } from '@/utils/filePicker.js';
import dayjs from "dayjs"
import { mapStores } from 'pinia'
import { random } from "@/uni_modules/uview-plus"
import graceRichText from "../config/rich-text-format.js"
import ChatInputBar from "../components/chat-input-bar.vue"
import Message from '@/pages/chat/message/components/Message.vue'
import ChatMixins from '../config/ChatMixins.js';
import PopoverMenu from '../components/PopoverMenu.vue';

export default {
	mixins: [ChatMixins],
	components: {
		ChatInputBar,
		Message,
		PopoverMenu
	},
	data () {
		return {
			hatBoxHeight: '0px',
			uploadOptions: {},
			safeAreaHeight: 0,
			talkList: [],// 聊天列表数据
			content: '',// 发送内容
			friend: {},
			imInfo: {},
			userInfo: {},
			index: 0,
			page: 1,
			emojiShow: false,
			dialogId: null,
			focus: false,
			recall: 0,
			thread: [],
			copyContent: '',
			chatBoxHeight: 0,
			nextCloud: {},
		}
	},
	computed: {
		...mapStores(useChatStore, useUserStore, useSocketStore, useCopyStore),
		lastMsg () {
			return this.socketStore.lastMsg;
		},
		// 页面高度
		pageHeight () {
			// #ifdef H5
			if (this.safeAreaHeight > 0) {
				return `height: calc(${this.safeAreaHeight}px - var(--window-top));`
			}
			return "";
			// #endif
			// #ifdef APP-PLUS
			return "";
			// #endif
		},
		setCopyImg () {
			return this.copyStore.copyValue.replace(':81', '');
		},
    isWorkNotice() {
      return (
        this.friend?.friend_account === 'sys_tasknotifier00000' ||
        this.friend?.username === '工作通知'
      )
    }
	},
	created () {
		const _self = this;
		this.safeAreaHeight = uni.getSystemInfoSync().safeArea.height;
		this.nextCloud = uni.getStorageSync('next_cloud');
		// #ifdef H5
		this.chatBoxHeight = '45px';
		// 初始化WS
		uni.getStorage({
			key: '_ws',
			success: function (res) {
				_self.socketStore.init(JSON.parse(res.data));
			}
		});
		this.friend = JSON.parse(uni.getStorageSync('friend'));// 当前聊天对象信息
		this.imInfo = JSON.parse(uni.getStorageSync('imInfo'));// 当前登录用户
		this.userInfo = JSON.parse(uni.getStorageSync('user')).user;
		this.dialogId = uni.getStorageSync('nowDialogId');
		// #endif

		// #ifdef APP-PLUS
		this.chatBoxHeight = '70px';
		this.friend = this.chatStore.chat;// 当前聊天对象信息
		this.imInfo = this.chatStore.imInfo || JSON.parse(uni.getStorageSync('imInfo'));// 当前登录用户
		this.userInfo = this.userStore.user;
		this.dialogId = this.socketStore.nowDialogId;
		// #endif
		
		uni.$on('setHaveRead', (data) => {
			this.setSendMsgRead(data);
		})

		uni.$on('setRecallMessage', (data) => {
			this.setRecall(data);
		})

		this.$nextTick(() => {
			this.getUnreadChatRecord();
			this.uploadOptions.url = `https://chat.mfarmers.com:88/phpApi/public/index.php/users/Index/uploadImg.html?account=${this.imInfo?.account}&to_account=${this.friend?.friend_account}&department=${this.imInfo?.department}`
		})
	},
	watch: {
		lastMsg: async function (newVal, oldVal) {
			const data = newVal.data;
			if (oldVal?.id && (newVal.id == oldVal.id)) return;
			if (this.dialogId == newVal.dialogId) {
				// 对图片 文件单独处理
				if (data.from.content2[0].type == 'img') {
					data.from.content2[0].html = await this.setImgUrl(data.from.content2[0].content);
				}
				if (data.from.content2[0].type == 'img/text') {
					data.from.content2[0].html = await this.setHtmlContent(data.from.content2[0].content);
				}

				if (newVal.relation_type && newVal.relation_type == 'reply') {
					const replyMsg = await chatApi(this.userInfo.token, {
						'data[id]': newVal.relation_id,
						'data[token]': this.userInfo.token,
						url: 'index.php/users/Index/getDialogInfo'
					})

					if (replyMsg.data) {
						replyMsg.data.content = JSON.parse(replyMsg.data.content);
						let { content, status, fromname } = replyMsg.data
						newVal.replyMsg = replyMsg.data;
						newVal.replyMsg.html = '';
						content.forEach(async (i) => {
							if (i.content != '') {
								newVal.replyMsg.html += await this.getQuoteContext(i, status, fromname);
							}
						});
					}
				}

				let lastMsg = {
					type: data.from.content2[0].type,
					content: data.from.content2,
					send_time: data.from.send_time,
					msg_id: newVal.msg_id,
					status: 11,
					id: newVal.id,
					fromavatar: data.from.avatar,
					fromname: data.from.username,
					from_phone: data.from.from_phone || data.from.phone,
					from_account: data.from.account,
					success: 'success',// 新发消息判断是否成功 loading true false
					client_id: newVal.client_id,
					replyMsg: newVal.replyMsg,
					relation_type: newVal.relation_type
				};

				if (data.from.account == this.imInfo.account) {
					lastMsg.status = 10;
				}

				this.$refs.paging.addChatRecordData(lastMsg);

				if (data.from.account === this.friend.friend_account) {
					this.setHaveRead(newVal);
				}
			}
		}
	},
  methods: {
		async copySend () {
			this.copyCancel();
			if (this.copyContent == ':/img/text') {
				const find = this.currentMsg.content.find(item => {
					return item.content !== '';
				})

				let sendMsg = {
					type: 'img/text',
					client_id: this.socketStore.client_id,
					content: [{
						type: 'img/text',
						content: this.copyStore.copyValue.content,
						html: this.copyStore.copyValue.html,
					}],
					send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
					status: 10,
					id: random(1000, 99999),
					fromavatar: this.imInfo?.avatar,
					fromname: this.imInfo?.username,
					from_phone: this.imInfo?.phone,
					from_account: this.imInfo?.account,
					success: 'loading',
					uuid: Math.random().toString(36).substring(2, 14)
				}
				this.$refs.paging.addChatRecordData(sendMsg);
				this.sendMessage(this.copyStore.copyValue.content, 'img/text', null, sendMsg);
			}
		
			if (this.copyContent == ':/image') {
				let sendMsg = {
					type: 'img',
					content: [{
						type: 'img',
						content: this.copyStore.copyValue,
						html: { url: this.copyStore.copyValue, width: 100, height: 100 },
					}],
					send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
					status: 10,
					id: random(1000, 99999),
					fromavatar: this.imInfo.avatar,
					fromname: this.imInfo.username,
					from_phone: this.imInfo.phone,
					from_account: this.imInfo.account,
					uuid: Math.random().toString(36).substring(2, 14),
					success: 'loading',
				}
				this.$refs.paging.addChatRecordData(sendMsg);
				this.sendMessage(this.copyStore.copyValue, 'img', null, sendMsg);
			}
		},
		replyMsgClick(replyMsg) {
			if(replyMsg.content && replyMsg.content[0]?.type == 'file') {
				this.openDoc(replyMsg, replyMsg.content[0], this.userInfo.worker_id)
			}
		},
		async queryList (pageNo, pageSize) {
			const params = {
				'data[account]': this.imInfo.account,
				'data[token]': this.userInfo.token,
				'data[myAccount]': this.imInfo.account,
				'data[page]': pageNo,
				'data[pageSize]': 30,
				'data[friendAccount]': this.friend.friend_account,
				url: 'index.php/users/Index/getChatRecord'
			}
			const msg = await chatApi(this.userInfo.token, params);
			if (msg.code == 200) {
				const cache = await Promise.all(msg.data.map(async (item) => {
					if (item.relation_type && item.relation_type == 'reply') {
						const replyMsg = await chatApi(this.userInfo.token, {
							'data[id]': item.relation_id,
							'data[token]': this.userInfo.token,
							url: 'index.php/users/Index/getDialogInfo'
						})

						if (replyMsg.data) {
							replyMsg.data.content = JSON.parse(replyMsg.data.content);
							let { content, status, fromname } = replyMsg.data
							item.replyMsg = replyMsg.data;
							item.replyMsg.html = '';
							content.forEach(async (i) => {
								if (i.content != '') {
									item.replyMsg.html += await this.getQuoteContext(i, status, fromname);
								}
							});
						}
					}
					item.content = this.checkContent(item.content);
					for (const content of item.content) {
						if (content.type === 'img') {
							content.html = await this.setImgUrl(content.content);
						}
						if (content.type === 'img/text') {
							content.html = await this.setHtmlContent(content.content);
						}

						if (content.type === 'apply') {
							try {
								// 把 apply 的 content 再解析一次
								content.applyData = JSON.parse(content.content);
								// 生成一个简单的 html 或展示文本，也可以直接渲染 applyData
								content.html = `
										<div class="apply-msg">
											<div class="apply-title">${content.applyData.title}</div>
											<div class="apply-status">状态：${content.applyData.status === 1 ? '已同意' : '待处理'}</div>
											<ul>
												${content.applyData.detail.map(d => `<li>${d.label}: ${d.value}</li>`).join('')}
											</ul>
										</div>
									`;
							} catch (e) {
								content.applyData = null;
								content.html = '审批单解析失败';
							}
						}

						if (content.type === 'apply_urge') {
							try {
								// 把 apply 的 content 再解析一次
								content.applyData = JSON.parse(content.content);
								// 生成一个简单的 html 或展示文本，也可以直接渲染 applyData
								content.html = `
									<div class="apply-msg">
										<div class="apply-title">${content.applyData.title}</div>
										<div class="apply-content">${content.applyData.content}</div>
									</div>
								`;
							} catch (e) {
								content.applyData = null;
								content.html = '审批单解析失败';
							}
						}

						if (content.type === 'apply_mention') {
							try {
								// 把 apply 的 content 再解析一次
								content.applyData = JSON.parse(content.content);
								// 生成一个简单的 html 或展示文本，也可以直接渲染 applyData
								content.html = `
									<div class="apply-msg">
										<div class="apply-title">${content.applyData.title}</div>
										<div class="apply-content">${content.applyData.content}</div>
									</div>
								`;
							} catch (e) {
								content.applyData = null;
								content.html = '审批单解析失败';
							}
						}

						if (content.type === 'log') {
						    try {
						      content.logData = JSON.parse(content.content);
						      content.html = `
										<div class="log-msg">
											<div class="log-title">${content.logData.title}</div>
											<div class="log-content">${content.logData.content}</div>
										</div>
						      `;
						    } catch (e) {
						      content.logData = null;
						      content.html = '日志内容解析失败';
						    }
						}

						// 新增 notice 类型数据解析
						if (content.type === 'notice') {
								try {
						      content.noticeData = JSON.parse(content.content);
						      content.html = `
						        <div class="notice-msg">
						          <div class="notice-tag">通知</div>
						          <div class="notice-title">${content.noticeData.title}</div>
						          <div class="notice-content">${content.noticeData.content}</div>
						        </div>
						      `;
						    } catch (e) {
						      content.noticeData = null;
						      content.html = '通知内容解析失败';
						    }
						}
					}

					return item
				}))

				cache.reverse();

				this.$refs.paging.complete(cache);
			} else {
				this.$refs.paging.complete([]);
			}
		},
		handleReply() {
			if (this.currentMsg.content[0].type == 'dir') {
				return
			}
			this.$refs.inputBar.setReplyContent(this.currentMsg);
		},
		async handleRevoke() {
			const current = new Date(this.currentMsg.send_time).getTime();
			const now = new Date().getTime();
			if ((now - current) > (this.recall * 1000)) {
				uni.showToast({
					icon: 'none',
					title: '已超出撤回时间无法撤回',
					duration: 1500
				})
				return
			}

			const params = {
				'data[account]': this.imInfo.account,
				'data[token]': this.userInfo.token,
				'data[myAccount]': this.imInfo.account,
				'data[messageId]': this.currentMsg.id,
				url: 'index.php/users/message/recall'
			}

			const msg = await chatApi(this.userInfo.token, params);

			if (msg.code == 200) {
				const findIndex = this.talkList.findIndex(item => {
					return item.id == this.currentMsg.id
				})
				this.talkList[findIndex].status = 12;
			}
		},
		setSendMsgRead (data) {
			this.talkList.some(item => {
				if (data.id == item.id) {
					item.status = 11;
				}
			})
		},
		async getUnreadChatRecord () {
			const params = {
				'data[page]': '',
				'data[pageSize]': '',
				'data[account]': this.imInfo.account,
				'data[token]': this.userInfo.token,
				'data[myAccount]': this.imInfo.account,
				'data[dialogId]': this.dialogId,
				url: 'index.php/users/Index/getUnReadChatRecord'
			}
			const msg = await chatApi(this.userInfo.token, params);

			if (msg.code == 200) {
				msg.data.forEach(item => {
					item.id = item.id
					this.setHaveRead(item);
				})
			}
		},
		// 设置已读
		async setHaveRead (record) {
			const params = {
				'data[account]': this.imInfo.account,
				'data[token]': this.userInfo.token,
				'data[myAccount]': this.imInfo.account,
				'data[id]': record.id,
				url: 'index.php/users/Index/setHaveRead'
			}
			const msg = await chatApi(this.userInfo.token, params);

			let haveRead = {
				type: 'haveRead',
				from: this.imInfo.account,
				to: msg.data.fromAccount,
				id: +record.id,
				readTime: msg.data.readTime
			};

			// 设置接收信息已读
			this.socketStore.send(haveRead);
		},
		// 信息发送
		async sendMessage(value, contentType, fileInfo, fileMsg) {
			try {
				let content = null;
				if (contentType === 'text') {
					content = `<p>${this.linkify(value)}</p>`
				} else {
					content = value;
				}
				
				// 处理消息发送数据
				const sendData = {
					type: 'chatMessage',
					timestamp: new Date().getTime(),
					msgId: `${this.imInfo?.account}_${new Date().getTime()}`,
					dialogId: this.dialogId,
					client_id: this.socketStore.client_id,
					data: {
						from: {
							fromType: 'friend',
							username: this.imInfo?.username,
							account: this.imInfo?.account,
							from_phone: this.imInfo?.phone,
							avatar: this.imInfo?.avatar || "",
							content: content,
							content_text: value,
							send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
							content2: [{
								type: contentType,
								content: content,
								myphone: this.imInfo?.phone,
								'friend-phone': this.friend?.friend_phone
							}],
						},
						to: {
							username: this.friend.username,
							account: this.friend.friend_account,
							to_phone: this.friend.friend_phone,
							avatar: this.friend.friend_avatar || "",
							type: 'friend',
						}
					}
				}
				if (this.$refs.inputBar.reply) {
					sendData.relation_id = this.currentMsg.id;
					sendData.relation_type = 'reply';
				}

				// 文件发送数据单独处理
				if (contentType == 'file') {
					sendData.data.from.content2 = [{
						uploadCompletedNum: 1,
						needUploadNum: 1,
						percentComplete: 100,
						content: '文件',
						icon: setIcon(fileInfo.name),// 根据后缀处理
						name: fileInfo.name,
						url: content,
						type: 'file',
						formatSize: fileInfo.isCopy ? fileInfo.formatSize : formatFileSize(fileInfo.size),
						localpath: ''
					}]
				}

				if (contentType == 'file' || contentType == 'img') {
					delete sendData.data.from.content;
					delete sendData.data.from.content_text;
					sendData.data.from.content2[0].fid = fileMsg.fid
				}

				// 将当前发送信息 添加到消息列表
				let lastMsg = null;

				if (fileMsg) {
					lastMsg = fileMsg;
				} else {
					lastMsg = {
						type: contentType,
						client_id: this.socketStore.client_id,
						content: sendData.data.from.content2,
						send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
						status: 10,
						id: random(1000, 99999),
						fromavatar: this.imInfo?.avatar,
						fromname: this.imInfo?.username,
						from_phone: this.imInfo?.phone,
						from_account: this.imInfo?.account,
						success: 'loading',
						uuid: Math.random().toString(36).substring(2, 14),
						relation_id: this.$refs.inputBar.reply ? sendData.relation_id : '',
						relation_type: this.$refs.inputBar.reply ? 'reply' : '',
					}
				}

				if (contentType == 'img') {
					lastMsg.content[0].html = await this.setImgUrl(lastMsg.content[0].content);
				}

				this.copyShow = false;

				const params = {
					'data[account]': this.imInfo?.account,
					'data[token]': this.userInfo?.token,
					'data[status]': 10,
					'data[friendAccount]': this.friend?.friend_account,
					'data[data]': JSON.stringify(sendData),
					url: 'index.php/users/Index/chatRecordAdd'
				}

				if (this.$refs.inputBar.reply) {
					let { content, status, fromname } = this.$refs.inputBar.currentMsg;
					lastMsg.replyMsg = this.currentMsg;
					lastMsg.replyMsg.html = '';
					lastMsg.replyMsg.from_username = fromname;
					content.forEach(async (i) => {
						if (i.content != '') {
							lastMsg.replyMsg.html += await this.getQuoteContext(i, status, fromname);
						}
					});
				}

				// 提前进入记录
				if (!fileMsg) {
					this.$refs.paging.addChatRecordData(lastMsg);
				}

				const msg = await chatApi(this.userInfo?.token, params);

				if (msg.code === 200) {
					this.$refs.inputBar.currentMsg = null;
					this.$refs.inputBar.reply = false;
					this.$refs.inputBar.replyData = '';
					// ws发送
					sendData.id = msg.data.reId;
					sendData.reId = msg.data.reId;
					sendData.msg_id = msg.data.msgId;
					sendData.unreadNum = msg.data.unreadNum;
					this.socketStore.send(sendData);
					this.setSendStatus(lastMsg, 'success', msg.data.msgId, msg.data.reId);
				} else {
					// 发送失败
					this.setSendStatus(lastMsg, 'error');
				}
				// 清空内容框中的内容
				this.$refs.inputBar.msg = '';
			} catch (error) {
				console.error('发送消息失败:', error);
				this.setSendStatus(lastMsg, 'error');
				this.$refs.inputBar.msg = '';
			}
			this.copyShow = false;
		},
		setSendStatus (lastMsg, status, msgId, id) {
			const find = this.talkList.find(item => item.uuid == lastMsg.uuid);
			find.success = status;
			if(msgId) {
				find.msg_id = msgId;
				find.id = id;
			}
		},
		// 发送按钮
		handleSendClick (msg) {
			if (msg == '') {
				return;
			}
			// 发送前将文本信息包裹在P标签中
			this.sendMessage(msg, 'text');
			// 清空输入框内容 - 新增代码
			this.$refs.inputBar.msg = '';
		},
		// 打开相机
		chooseCamera () {
			uni.chooseImage({
				count: 1, //默认9
				sizeType: ['original'],
				sourceType: ['camera'],
				success: (res) => {
					res.tempFilePaths.forEach((filePath) => {
						let lastMsg = {
							type: 'img',
							content: [{
								type: 'img',
								content: filePath, // 先用本地路径
								html: { url: filePath, width: 100, height: 100 }, // 临时显示
							}],
							send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
							status: 10,
							id: random(1000, 99999),
							fromavatar: this.imInfo.avatar,
							fromname: this.imInfo.username,
							from_phone: this.imInfo.phone,
							from_account: this.imInfo.account,
							localpath: filePath,
							percentage: 0, // 进度
							uuid: Math.random().toString(36).substring(2, 14),
							success: 'loading',
						}

						this.$refs.paging.addChatRecordData(lastMsg);
						this.uploadImgOrFile(filePath, null, lastMsg);
					});
				}
			});
		},
		// 打开相册
		chooseImage () {
			uni.chooseImage({
				count: 9, //默认9
				sizeType: ['original'],
				sourceType: ['album'],
				success: (res) => {
					res.tempFilePaths.forEach((filePath) => {

						let lastMsg = {
							type: 'img',
							content: [{
								type: 'img',
								content: filePath, // 先用本地路径
								html: { url: filePath, width: 100, height: 100 }, // 临时显示
							}],
							send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
							status: 10,
							id: random(1000, 99999),
							fromavatar: this.imInfo.avatar,
							fromname: this.imInfo.username,
							from_phone: this.imInfo.phone,
							from_account: this.imInfo.account,
							localpath: filePath,
							percentage: 0, // 进度
							uuid: Math.random().toString(36).substring(2, 14),
							success: 'loading',
						}

						this.$refs.paging.addChatRecordData(lastMsg);
						this.uploadImgOrFile(filePath, null, lastMsg);
					});
				}
			});
		},
		beforUpload (e) {
			let lastMsg = {
				type: 'file',
				content: [{
					uploadCompletedNum: 1,
					needUploadNum: 1,
					percentComplete: 100,
					content: '文件',
					icon: setIcon(e.fileName),// 根据后缀处理
					name: e.fileName,
					url: '',
					type: 'file',
					formatSize: formatFileSize(e.fileSize),
					localpath: ''
				}],
				send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
				status: 10,
				id: random(1000, 99999),
				fromavatar: this.imInfo?.avatar,
				fromname: this.imInfo?.username,
				from_phone: this.imInfo?.phone,
				from_account: this.imInfo?.account,
				percentage: 0,
				uuid: e.uuid,
				success: 'loading',
			};
			this.$refs.paging.addChatRecordData(lastMsg);
		},
		// 上传 图片 文件
		uploadImgOrFile (filePath, fileInfo, lastMsg = null) {
			const upUrl = `https://chat.mfarmers.com:88/phpApi/public/index.php/users/Index/uploadImg.html?account=${this.imInfo.account}&to_account=${this.friend.friend_account}&department=${this.imInfo.department}`
			// 文件上传提前推入tasklist 添加上传标志
			// let lastMsg = {};
			if (fileInfo && !lastMsg) {
				lastMsg = {
					type: 'file',
					content: [{
						uploadCompletedNum: 1,
						needUploadNum: 1,
						percentComplete: 100,
						content: '文件',
						icon: setIcon(fileInfo.name), // 根据后缀处理
						name: fileInfo.name,
						url: '',
						type: 'file',
						formatSize: formatFileSize(fileInfo.size),
						localpath: ''
					}],
					send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
					status: 10,
					id: random(1000, 99999),
					fromavatar: this.imInfo.avatar,
					fromname: this.imInfo.username,
					from_phone: this.imInfo.phone,
					from_account: this.imInfo.account,
					percentage: 0,
					uuid: Math.random().toString(36).substring(2, 14),
					success: 'loading',
				};

				this.$refs.paging.addChatRecordData(lastMsg);
			}
			const uploadTask = uni.uploadFile({
				url: upUrl,
				filePath: filePath,
				name: 'tmp_name',
				success: (uploadFileRes) => {

					const data = JSON.parse(uploadFileRes.data);
					const msgIndex = this.talkList.findIndex(msg =>
						msg.id === lastMsg.id || msg.uuid === lastMsg.uuid
					);
					if (data.data.startsWith("http://chat.mfarmers.com:81")) {
						data.data = data.data.replace("http://chat.mfarmers.com:81/", "https://chat.mfarmers.com:88/");
					}

					// 上传成功 -> 更新 lastMsg
					if (msgIndex !== -1) {
						// this.talkList[msgIndex].uploading = false;
						this.talkList[msgIndex].percentage = 100;
						if (fileInfo) {
							this.talkList[msgIndex].content[0].url = data.data;
							this.talkList[msgIndex].fid = data.id;
							this.sendMessage(data.data, 'file', fileInfo, this.talkList[msgIndex]);
						} else {
							this.talkList[msgIndex].content[0].content = data.data;
							this.talkList[msgIndex].content[0].html.url = data.data;
							this.talkList[msgIndex].fid = data.id;
							this.sendMessage(data.data, 'img', null, this.talkList[msgIndex]);
						}
					}
				}
			});

			// H5端监听进度
			// #ifdef H5
			if (fileInfo) {
				this.thread.push({
					uploadTask: uploadTask,
					uuid: lastMsg.uuid
				})
				uploadTask.onProgressUpdate((res) => {
					this.setProgress(lastMsg.uuid, res.progress);
				});
			}
			// #endif

			uploadTask.onProgressUpdate((res) => {
				const msgIndex = this.talkList.findIndex(msg =>
					msg.id === lastMsg.id || msg.uuid === lastMsg.uuid
				);
				if (msgIndex !== -1) {
					this.talkList[msgIndex].progress = res.progress;
				}
			});
		},
		// 打开聊天设置弹窗
		rightClick () {
			uni.navigateTo({
				url: '/pages/chat/message/chat/setting'
			})
		},
		// 调用拨号
		async callPhone () {
			const phoneNumber = this.friend.friend_phone
			try {
				// #ifdef APP-PLUS
				await this.checkCallPermission();
				// #endif
				uni.makePhoneCall({
					phoneNumber: phoneNumber,
					success: () => {
						console.log('拨号成功')
					},
					fail: (err) => {
						console.error('拨号失败:', err);
						// 特殊处理国产手机
						this.handleManufacturerPermission(phoneNumber);
					}
				});
			} catch (error) {
				console.log(error)
				if (error === 'PERMISSION_DENIED_ALWAYS') {
					this.showPermissionGuide(); // 显示权限引导
				} else {
					uni.showToast({ title: '拨号权限被拒绝', icon: 'none' });
				}
			}
		},
		// 检查并申请电话权限
		async checkCallPermission () {
			return new Promise((resolve, reject) => {
				// #ifdef APP-PLUS
				if (plus.os.name === 'Android') {
					// 先检查当前是否已有权限
					plus.android.checkPermission('android.permission.CALL_PHONE',
						(e) => {
							if (e.success) {
								resolve(); // 已有权限
							} else {
								// 没有权限则申请
								plus.android.requestPermissions(
									['android.permission.CALL_PHONE'],
									(result) => {
										// 修改判断逻辑
										const granted = result.granted ||
											(result.denied.length === 0 &&
												result.deniedAlways.length === 0);
										granted ? resolve() : reject('PERMISSION_DENIED');
									},
									(err) => reject(err)
								);
							}
						},
						(err) => reject(err)
					);
				} else {
					resolve(); // iOS无需动态申请
				}
				// #endif

				// #ifndef APP-PLUS
				resolve(); // 非APP端无需处理
				// #endif
			});
		},
		// 处理国产手机特殊权限
		handleManufacturerPermission (phoneNumber) {
			// 小米、华为等可能需要额外权限
			if (plus.os.vendor === 'xiaomi' || plus.os.vendor === 'huawei') {
				uni.showModal({
					title: '权限提示',
					content: '请在系统设置中开启「电话」和「后台弹出界面」权限',
					confirmText: '去设置',
					success: (res) => {
						if (res.confirm) plus.runtime.openSettings();
					}
				});
			} else {
				// 尝试直接调用系统拨号界面
				plus.runtime.openURL(`tel:${phoneNumber}`);
			}
		},
		// 显示权限引导
		showPermissionGuide () {
			uni.showModal({
				title: '权限被永久拒绝',
				content: '需要电话权限才能拨号，请前往应用设置手动开启',
				confirmText: '去设置',
				success: (res) => {
					if (res.confirm) {
						// 跳转到应用详情页
						plus.runtime.openSettings();
					}
				}
			});
		},
		jumpPerson (e) {
			let params = {
				id: e.wid,
				name: e.fromname,
				type: 'user',
				avatar: e.fromavatar
			}
			uni.navigateTo({
				url: '/pages/addressBook/details/grdetails',
				animationType: 'none',
				success: function (res) {
					res.eventChannel.emit('details', { item: params })
				}
			});
		}
	}
}
</script>
<style lang="scss">
@import "../config/global.scss";

.chat-container {
	::v-deep .zp-view-super {
		padding-bottom: 10px !important;
	}
}
</style>